
//--> Loth 2011 
//--> Away3d engine & interface init

package chamans.engine
{
	import away3d.filters.*;
	import away3d.materials.*;
	import away3d.containers.*;
	import away3d.debug.AwayStats;
	import away3d.materials.methods.*;
	import away3d.containers.ObjectContainer3D;
	import away3d.events.*;
	import away3d.loaders.*;
	import away3d.loaders.parsers.*;
	
	import chamans.away.*;
	import chamans.*;
	
	import flash.ui.*;
	import flash.geom.*;
	import flash.events.*;
	import flash.system.*;
	import flash.net.*;
	import flash.display.*;
	import flash.utils.Timer;
	
	public class Away4 extends Sprite
	{
		public static var stage:Stage;
		public var FlashLimiteVersion:Array=[10, 0, 3, 181];
		public var physicEngine:String;
		public var Engine:String;
		public var act:Boolean=false
		// chamans 
		public var KEY:key;
		public var LOAD:load;
		public var TOOL:Tool;
		public var SYS:Interface;
		public var PAUSE:PauseScreen;
		// init variable
		private var END:Function;
		private var LOOP:Function;
		private var def:Object;
		// basic variable ?
		public var autoMove:Boolean=false;
		public var mouseHide:Boolean=false;
		public var MenuActif:Boolean=false;
		// resize variable
		public var limite:Boolean=true;
		public var size:Point=new Point(0,0);
		public var sizelimit:Point=new Point(800,450);
		
		//______________________o
		// away3d variable
		public var LIGHT:Array;	
		public var NReflect:Vector.<Number>;
		public var phyOn:Boolean=true;
		public var fog:Boolean;
		public var FogOn:Boolean=false;
		public var reflect:Boolean;
		public var physics:*;
		public var FogColor:int;
		public var FogDistance:int;
		private var ciel:Boolean;	
		// away3d
		public var view:View3D;
		public var FOG:FogMethod;
		public var CurrentFilter:Filter3DBase;
		public var MatListe:Vector.<DefaultMaterialBase>;
		public var MatReflect:Vector.<DefaultMaterialBase>;
		public var FogShader:Vector.<FogMethod>;
		// chamans away
		public var Lights:light;
		public var Camera:cameralo;	
		public var SKY:sky;
		// loader variable
		private var TMP:Array;
		private var n:int=-1;
		
		private function OO(event:Event=null):void
		{
			//	GETKEYS()
			if (phyOn) physics.update();
			//	if (Lights) Lights.update();
			if (Camera) Camera.update();
			if(LOOP!=null)LOOP()
			if (view)view.render();
		}
		public function Away4(end:Function=null, loop:Function=null, setting:Object=null)
		{
			Engine="away3d";
			END=end;
			LOOP=loop;
			phyOn = setting.phy;
			TMP=new Array();
			
			def = setting || new Object();
			fog=def.fog || true;
			ciel=def.sky || true;
			reflect=def.reflect || false;
			
			if(stage) init(); //--> flash builder
			else addEventListener(Event.ADDED_TO_STAGE,onStage);//--> flash cs5
		}
		public function info():String { return view.renderedFacesCount.toString(); }
		private function onStage(e:Event):void
		{
			removeEventListener(Event.ADDED_TO_STAGE,onStage);
			init();
		}
		private function init():void
		{
			//_______chamans usefull utils
			LOAD = new load(); TOOL = new Tool(); KEY = new key(stage);
			// stage set
			with (stage){ align = "TL"; scaleMode = "noScale"; quality = "HIGH"; }
			init_2D();
		}
		
		//_______________________________________________2D interface init
		private function init_2D():void
		{
			SYS = new Interface( this, init_VIEW3D, def);
			addChild(SYS);
		}
		//_______________________________________________3d Engine init
		private function init_VIEW3D():void
		{
			view = new View3D();
			view.mouseEnabled=false;
			view.mouseChildren=false;
			view.antiAlias = def.Q || 0;
			view.backgroundColor = 0x000000;
			addChild(view);
			
			MatListe = new Vector.<DefaultMaterialBase>();
			MatReflect = new Vector.<DefaultMaterialBase>();
			NReflect = new Vector.<Number>();
			
			Camera = new cameralo(this, def.fov || 45,def.far || 4000, def.near || 1);
			with (Camera.M){ type = def.type || "normal"; H = def.H || 90; V = def.V || 90; 
				distance = def.targetDistance || 1000;
				baseTarget = def.position || new Vector3D(0,0,500);
			}
			Lights = new light(this);
			
			FogDistance = def.color[4] || 500;
			FogColor = def.color[3] || 0xCC;
			FogShader = new Vector.<FogMethod>();
			RESIZE();
			Active();
			act=true;
			if(ciel)SKY = new sky(this,'vector',def.color || [ 0xFF, 0x66, 0x11, 0xCC, 500, 1, .8, true ] );
			if(END!=null)END();
		}
		//_______________________________________________rezise
		public function RESIZE(e:Event=null):void
		{
			size=new Point( stage.stageWidth, stage.stageHeight);
			SYS.OUT("resize "+size.x+" "+size.y);
			if(SYS.actif)SYS.cadre(size);
			if(PAUSE) PAUSE.Resize();
			if(view) RESIZE3D();
			if(limite && size.x==sizelimit.x && size.y==sizelimit.y)activeResize(false);	
		}
		public function RESIZE3D(e:Event=null):void
		{
			Camera.Resize();
			view.width = size.x;
			view.height = size.y;
		}
		//_______________________________________________Pause screen
		private function Active(e:Event=null):void
		{
			stage.removeEventListener(Event.ACTIVATE,Active);
			stage.addEventListener(Event.ENTER_FRAME, OO, false, 0, true);
			stage.addEventListener(Event.DEACTIVATE,Desactive, false, 0, true);
			if(PAUSE!=null){PAUSE.clear(); removeChild(PAUSE);PAUSE=null};
		}
		private function Desactive(e:Event):void 
		{
			stage.removeEventListener(Event.ENTER_FRAME, OO);
			stage.removeEventListener(Event.DEACTIVATE,Desactive);
			stage.addEventListener(Event.ACTIVATE,Active, false, 0, true);
			if(PAUSE==null) PAUSE=new PauseScreen(this); addChild(PAUSE);
		}
		public function activeResize(n:Boolean=true):void 
		{
			if(n)stage.addEventListener('resize',  RESIZE, false, 0, true);
			else {stage.removeEventListener('resize',  RESIZE); 
				SYS.OUT(SYS.MESSAGE);
		}}
		
		//_______________________________________________Keyboard
		private function GETKEYS(e:Event=null):void 
		{	
			/*if( KEY.isDown( 49 ) || KEY.isDown( 97 )){ physics.MinitionType=0; }//1
			if( KEY.isDown( 50 ) || KEY.isDown( 98 )){ physics.MinitionType=1; }//2
			if( KEY.isDown( 51 ) || KEY.isDown( 99 )){ physics.MinitionType=2; }//3
			if( KEY.isDown( 52 ) || KEY.isDown( 100 )){ physics.MinitionType=3; }//4*/
		}
		//_______________________________________________Shadow filter
		public function Shadows( n:int=0 ):void
		{
			var ShadowFilter:ShadingMethodBase
			switch(n){
				case 0: ShadowFilter = null; break;
				case 1: ShadowFilter = new SoftShadowMapMethod(LIGHT[0]); break;
				case 2: ShadowFilter = new FilteredShadowMapMethod(LIGHT[0]); break;
				case 3: ShadowFilter = new HardShadowMapMethod(LIGHT[0]); break;
			}
			for each( var m:DefaultMaterialBase in MatListe) if(m as BitmapMaterial )if( !m.bothSides)m.shadowMethod = ShadowFilter;
		}
		//_______________________________________________Fog filter
		public function Foger(F:Boolean=true):void
		{
			var i:int;
			if (F && !FogOn){FogOn=true;
				for(i=0;i<MatListe.length;++i)MatListe[i].addMethod(FogShader[i]);	
			} 
			if(!F){FogOn=false;
				for(i=0;i<MatListe.length;++i)MatListe[i].removeMethod(FogShader[i]);
		}}
		public function F_Fog(M0:DefaultMaterialBase, M1:DefaultMaterialBase=null,M2:DefaultMaterialBase=null,M3:DefaultMaterialBase=null):void
		{
			var NewFog:FogMethod = new FogMethod(FogDistance, FogColor);
			M0.addMethod(NewFog); FogShader.push(NewFog);
			if(M1){M1.addMethod(NewFog); FogShader.push(NewFog);}
			if(M2){M2.addMethod(NewFog); FogShader.push(NewFog);}
			if(M3){M3.addMethod(NewFog); FogShader.push(NewFog);}
		}
		public function distance_Fog(n:int=10):void { for each( var G:FogMethod in FogShader) G.fogDistance=n; }
		public function color_Fog():void { for each( var G:FogMethod in FogShader) G.fogColor=FogColor; }
		//_______________________________________________Reflect map
		public function F_reflect(M:DefaultMaterialBase, a:Number=1):void
		{if(SKY.envMap!=null && reflect){ M.addMethod( new EnvMapMethod(SKY.envMap, a));}
			MatReflect.push(M);
			NReflect.push(a);
		}
		//_______________________________________________3D Filters
		public function Deep(x:int=10, y:int=10, range:int=1500):void
		{
			var Filter:DepthOfFieldFilter3D = new DepthOfFieldFilter3D(x, y);
			Filter.range = range;
			CurrentFilter=Filter;
			view.filters3d = [ Filter ];
		}
		public function Bloom(x:int=10, y:int=10, threshold : Number = .75, exposure:Number = .5, quality:int = 0):void
		{
			var Filter:BloomFilter3D = new BloomFilter3D(x, y, threshold,exposure , quality );
			CurrentFilter=Filter;
			view.filters3d = [ Filter ];
		}
		public function MotionBlur(strength:Number=.65):void
		{
			var Filter:MotionBlurFilter3D = new MotionBlurFilter3D(strength);
			CurrentFilter=Filter;
			view.filters3d = [ Filter ];
		}
		public function Blur(x:int=4, y:int=4):void
		{
			var Filter:BlurFilter3D = new BlurFilter3D(x,y);
			CurrentFilter=Filter
			view.filters3d = [ Filter ];
		}
		//_______________________________________________OBJ loader
		public function OBJ3D( link:String, F:Function=null ):void
		{
			n++
				TMP.push(F || new Function());
			Loader3D.enableParser(OBJParser);
			var loader:Loader3D = new Loader3D();
			loader.name=n.toString()
			loader.addEventListener(LoaderEvent.RESOURCE_COMPLETE, OBJ3DLoaded);
			loader.addEventListener(LoaderEvent.DEPENDENCY_ERROR, ERROR);
			if(SYS.ID!=-1) link=link+"?uniq="+SYS.ID
			loader.load(new URLRequest(link));
		}
		private function OBJ3DLoaded(e:LoaderEvent):void
		{
			var container:ObjectContainer3D=(e.target as ObjectContainer3D)
			TMP[e.target.name](container)
			SYS.OUT(SYS.MESSAGE)
		}
		private function ERROR( e:IOErrorEvent ):void { SYS.OUT("IOerror "+"OBJECT not found");}
		private function inProgress(e:ProgressEvent) :void
		{
			var P:int = int(e.bytesLoaded / e.bytesTotal * 100), ko:int =(e.bytesLoaded / 1024)<<0;
			SYS.OUT( "Loading: "+"OBJECT"+" | " +P+"% | "+ ko +' Ko' )
		}
		//_______________________________________________Time pause
		public function Pause ( END:Function ):void
		{
			tmpFunction=END;
			time = new Timer(delay, 1 );
			time.start();
			time.addEventListener(TimerEvent.TIMER_COMPLETE, completeHandler);
		}
		private function completeHandler(e:TimerEvent):void 
		{
			time.removeEventListener(TimerEvent.TIMER_COMPLETE, completeHandler);
			tmpFunction();
			time.stop();
		}
		
		private var time:Timer;
		private var delay:uint = 1000;//1000 = 1 seconde
		private var tmpFunction:Function;
		
		
	}}